﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

using Syncfusion.Drawing;
using Syncfusion.Grouping;
using Syncfusion.Windows.Forms;
using Syncfusion.Windows.Forms.Grid;
using Syncfusion.Windows.Forms.Grid.Grouping;

using PMngr.Data;

namespace PMngr.Main
{
    public partial class Options : BaseControl, IControl
    {
        private IRepositoryFactory repositoryFactory;

        public Options()
        {
            InitializeComponent();
            // GridGroupingControl
            InitializeGridGrouping();           
        }

        public Options(IRepositoryFactory repositoryFactory) : this()
        {
            this.repositoryFactory = repositoryFactory;
        }

        public override void InitializeControls()
        {
            InitializeGridList();
            //
            comOptionType_SelectionChangeCommitted(this, EventArgs.Empty);
        }

        private void InitializeGridList()
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var options = repository.All<ItemBase>();
                var datasource = from o in options
                                 where o.Type == "OptionType"
                                 orderby o.Order ascending
                                 select new {Name = o.Name, Description = o.Description, ImageIndex = 0};
                var result = datasource.ToList();
                this.gridListOptions.DataSource = result;
                this.gridListOptions.DisplayMember = "Description";
                this.gridListOptions.ValueMember = "Name";
                // 增强型需求
                this.gridListOptions.ImageList = this.imageList;
            }
        }

        #region GridGroupingControl Settings
        private void InitializeGridGrouping()
        {
            foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(typeof(ItemModel)))
            {
                GridColumnDescriptor gcd = new GridColumnDescriptor(pd.Name, pd.Name, ItemModel.Dict[pd.Name], true, 80);
                if (pd.Name == "Description") gcd.Width = 200;

                this.glOptions.TableDescriptor.Columns.Add(gcd);
            }
            // hide the trivial items
            this.glOptions.TableDescriptor.VisibleColumns.Remove("Code");
            this.glOptions.TableDescriptor.VisibleColumns.Remove("IsValid");
            this.glOptions.TableDescriptor.VisibleColumns.Remove("Type");
            this.glOptions.TableDescriptor.AllowNew = false;
            this.glOptions.TableDescriptor.Appearance.AnyRecordFieldCell.CellType = "Static";

            glOptions.InitializeGridGroupingWithFormat("[IsValid] LIKE 'false'");
            
            glOptions.DataSource = null;
            // event
            glOptions.TableControlMouseDown += glOptions_TableControlMouseDown;
        }
        #endregion

        #region Private methods
        private void SetOptionDetails(OptionEventArgs e)
        {
            var item = e.Option;
            addOption.Name = item.Name;
            addOption.Desc = item.Description;
            addOption.Order = item.Order;
            addOption.IsValid = item.IsValid;
        }
        private void ResetAddOption()
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                string type = this.comOptionType.ListControl.SelectedValue.ToString();
                var order = repository.Find<ItemBase>(item => item.Type == type).Max(item => item.Order);
                addOption.Name = "";
                addOption.Desc = "";
                addOption.Order = ++order;
                addOption.IsValid = true;
            }
        }
        private void ResetGrid(string type, int selected)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var datasource =
                    repository.Find<ItemBase>(item => item.Type == type).OrderBy(item => item.Order).ToList();
                this.glOptions.DataSource = datasource;
            }
           
            if (this.glOptions.Table.Records.Count > 0)
            {
                this.glOptions.Table.SelectedRecords.Add(this.glOptions.Table.Records[selected]);
                this.glOptions.Table.CurrentRecord = this.glOptions.Table.Records[selected];
            }
        }
        #endregion

        #region Save Options
        private bool CheckName(string name, string type)
        {
            using (var repository = repositoryFactory.CreateRepository())
            {
                var items = repository.Find<ItemBase>(i => i.Name == name && i.Type == type);
                if (items.Count() > 0)
                    return true;
                return false;
            }
        }

        private void addOption_UpdateHandler(object sender, EventArgs e)
        {
            if (String.IsNullOrWhiteSpace(addOption.Name))
            {
                MessageFactory.Show(Utilities.OptionNameRequired, MessageType.Exclamation);
                return;
            }

            var type = this.comOptionType.ListControl.SelectedValue.ToString();
            var isExist = CheckName(addOption.Name, type);

            using (var repository = repositoryFactory.CreateRepository())
            {
                Record selected;
                var selecteds = this.glOptions.Table.SelectedRecords;
                try
                {
                    if (selecteds != null && selecteds.Count > 0)
                    {
                        selected = selecteds[0].Record;
                        var item = selected.GetData() as ItemBase;
                        if (item == null) return;
                        // Validate the ItemBase model
                        if ((item.Name != addOption.Name) && isExist)
                        {
                            MessageFactory.Show(String.Format(Utilities.NameDuplicated, addOption.Name),
                                                MessageType.Exclamation);
                            return;
                        }
                        //
                        var option = repository.Find<ItemBase>(item.Code);
                        option.Name = addOption.Name;
                        option.Description = addOption.Desc;
                        option.Order = addOption.Order;
                        option.IsValid = addOption.IsValid;

                        repository.CommitChanges();
                        //
                        int index = this.glOptions.Table.Records.IndexOf(selected);
                        ResetGrid(item.Type, index);

                        LogTrace(String.Format(Utilities.SuccessOptionUpdated, item.Name), MessageType.Information);
                    }
                    else
                    {
                        if (isExist)
                        {
                            MessageFactory.Show(String.Format(Utilities.NameDuplicated, addOption.Name),
                                                MessageType.Exclamation);
                            return;
                        }
                        var item = new ItemBase
                                       {
                                           Type = type,
                                           Name = addOption.Name,
                                           Description = addOption.Desc,
                                           Order = addOption.Order,
                                           IsValid = addOption.IsValid
                                       };

                        repository.Add(item);
                        repository.TrySave<ItemBase>();
                        ResetGrid(item.Type, 0);

                        LogTrace(String.Format(Utilities.SuccessOptionAdded, item.Name));
                    }
                }
                catch (ValidationException ex)
                {
                    string message = String.Empty;
                    foreach (var entity in ex.Errors)
                    {
                        foreach (var error in entity.Errors)
                            message += String.Format("Property:'{0}' Error:{1}\r\n", error.Property, error.Message);
                    }
                    LogTrace(message, MessageType.Error);
                }
            }
        }
        #endregion

        private void glOptions_SelectedRecordsChanged(object sender, SelectedRecordsChangedEventArgs e)
        {
            var selecteds = this.glOptions.Table.SelectedRecords;
            if (selecteds != null && selecteds.Count > 0)
            {
                var selected = selecteds[0].Record.GetData() as ItemBase;
                SetOptionDetails(new OptionEventArgs(selected));
            }            
            else
            {
                ResetAddOption();
            }
        }

        void glOptions_TableControlMouseDown(object sender, GridTableControlMouseEventArgs e)
        {
            if (e.Inner.Button == MouseButtons.Right)
            {
                int row = 0;
                int col = 0;
                Point pt = new Point(e.Inner.X, e.Inner.Y);

                if (e.TableControl.PointToRowCol(pt, out row, out col))
                    e.TableControl.CurrentCell.AdjustRowColIfCoveredCell(ref row, ref col);

                GridTableCellStyleInfo style = e.TableControl.GetTableViewStyleInfo(row, col);
                if (style.TableCellIdentity.DisplayElement.Kind != DisplayElementKind.ColumnHeader)
                    this.contextMenu.Show(e.TableControl, pt);
            }
        }

        private void comOptionType_SelectionChangeCommitted(object sender, EventArgs e)
        {
            var selected = this.comOptionType.ListControl.SelectedValue;
            if (selected != null)
            {
                string type = selected.ToString();

                ResetGrid(type, 0);
            }
        }
        
        private void AddNewItemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Grid
            this.glOptions.Table.SelectedRecords.Clear();
            // UserControl
            ResetAddOption();
        }


    }

    
}
